#include <stdio.h>
#include <stdlib.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <ESP8266WiFi.h>
#include <ESP8266WiFiMulti.h>  
ESP8266WiFiMulti wifiMulti; 

#include <NTPClient.h>
#include <WiFiUdp.h>

#include <PubSubClient.h>
#include <Ticker.h>

#include <dht11.h>//引入DHT11库
/********************###定义###********************/
dht11 DHT11;//定义传感器类型
#define DHT11PIN 2//定义传感器连接引脚。此处的PIN2在NodeMcu8266开发板上对应的引脚是D4

// const char* ssid     = "Openwrt-fast";  
// const char* password = "zk010823";   

// const char* mqttServer = "test.ranye-iot.net";
// const char* mqttServer = "mqtt.beesoft.ink";
const char* mqttServer = "118.31.36.131";

Ticker ticker;
WiFiClient wifiClient;
PubSubClient mqttClient(wifiClient);

int count;    // Ticker计数用变量

float humidity;
float temperature;


Adafruit_SSD1306 display(128, 64, &Wire, -1);

WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "ntp.aliyun.com"); //NTP地址
 
void setup() {
  Serial.begin(115200); 

  wifiMulti.addAP("Openwrt-fast", "zk010823"); 
  wifiMulti.addAP("Openwrt", "zk010823"); 
                        
  Serial.print("DHT11库文件版本: ");
  Serial.println(DHT11LIB_VERSION);

  // WiFi.mode(WIFI_STA);
  // WiFi.begin(ssid, password);
  // while (WiFi.status() != WL_CONNECTED) {
  //   delay(500);
  //   Serial.print(".");
  // }

 Serial.println("Connecting ...");         
  int i = 0;                                 
  while (wifiMulti.run() != WL_CONNECTED) {  
    delay(1000);                             
    Serial.print('.');                       
  }                                          

  Serial.println('\n');               
  Serial.print("WiFi Connected to ");          
  Serial.println(WiFi.SSID());              
  Serial.print("IP address:\t");           
  Serial.println(WiFi.localIP());           

  // 设置MQTT服务器和端口号, 连接MQTT服务器
  mqttClient.setServer(mqttServer, 1883);
  // mqttClient.setServer(mqttServer, 8080);
  connectMQTTServer();
  // Ticker定时对象
  ticker.attach(1, tickerCount);  


  timeClient.begin();
  timeClient.setTimeOffset(28800); //+1区，偏移3600，+8区，偏移3600*8

  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
    Serial.println(F("SSD1306 allocation failed"));
    for (;;);
  }
  delay(2000);
  display.clearDisplay();
  display.setTextColor(WHITE);
}

int flag = 1;


void loop() {
  Serial.println(millis());

  timeClient.update();
  unsigned long epochTime = timeClient.getEpochTime();
  Serial.print("Epoch Time:");
  Serial.println(epochTime);
 
  //打印时间
  int currentHour = timeClient.getHours();
  int currentMinute = timeClient.getMinutes();
  int currentSecond = timeClient.getSeconds();
  //将epochTime换算成年月日
  struct tm *ptm = gmtime((time_t *)&epochTime);
  int year = ptm->tm_year;
  int monthDay = ptm->tm_mday;
  int currentMonth = ptm->tm_mon + 1;
  Serial.print("DateTime:"); 
  Serial.print(year+1900); Serial.print("-");Serial.print(currentMonth);Serial.print("-");Serial.print(monthDay);Serial.print(" "); 
  Serial.print(currentHour);Serial.print(":");Serial.print(currentMinute);Serial.print(":");Serial.print(currentSecond);
  
  // 刷新显示内容
  delay(2000);
  // 清空显示
  display.clearDisplay();
  // 使更改的显示生效
  display.display();

  // 判断应该显示的内容
  flag = flag % 2;

  if (flag == 1) {

    display.setTextSize(1);  // 设置字体大小（1~8）
    display.setCursor(0, 0); // 设置坐标
    display.print("Time:"); // 显示内容
    display.setTextSize(2);
    display.setCursor(0, 15);
    display.print(year+1900);display.print("-");display.print(currentMonth);display.print("-");display.print(monthDay);

    display.setCursor(0, 40);
    display.print(currentHour);display.print(":");display.print(currentMinute);display.print(":");display.print(currentSecond);
  } 
  
  
  if (flag == 0) {

    //更新传感器所有信息
    DHT11.read(DHT11PIN); 
    humidity = (float)DHT11.humidity;
    temperature = (float)DHT11.temperature;

    Serial.print("当前湿度 (%): ");
    Serial.println(humidity, 2);
    Serial.print("当前温度 (℃): ");
    Serial.println(temperature, 2);

    // show temp
    display.setTextSize(1);
    display.setCursor(0, 0);
    display.print("Temperature: ");
    display.setTextSize(2);
    display.setCursor(0, 15);
    // display.print(28.6);
    display.print(temperature);

    display.print(" ");
    display.setTextSize(1);
    display.cp437(true);
    display.write(167);
    display.setTextSize(2);
    display.print("C");

    // show humidity
    display.setTextSize(1);
    display.setCursor(0, 0+35);
    display.print("Humidity: ");
    display.setTextSize(2);
    display.setCursor(0, 15+35);
    // display.print(46);
    display.print(humidity);
    display.print(" %");

    // delay(1000);
  }

  flag++;

  display.display();

  //-------------------------------------------------------------
  if (mqttClient.connected()) { // 如果开发板成功连接服务器
    // 每隔3秒钟发布一次信息
    if (count >= 3){
      pubMQTTmsg();
      count = 0;
    }    
    // 保持心跳
    mqttClient.loop();
  } else {                  // 如果开发板未能成功连接服务器
    connectMQTTServer();    // 则尝试连接服务器
  }

}


void tickerCount(){
  count++;
}
 
 
void connectMQTTServer(){
  // 根据ESP8266的MAC地址生成客户端ID（避免与其它ESP8266的客户端ID重名）
  String clientId = "esp8266-" + WiFi.macAddress();
 
  // 连接MQTT服务器
  if (mqttClient.connect(clientId.c_str())) { 
    Serial.println("MQTT Server Connected.");
    Serial.println("Server Address: ");
    Serial.println(mqttServer);
    Serial.println("ClientId:");
    Serial.println(clientId);
  } else {
    Serial.print("MQTT Server Connect Failed. Client State:");
    Serial.println(mqttClient.state());
    delay(3000);
  }   
}
 
// 发布信息 - 温度， 湿度
void pubMQTTmsg(){

  // String topicString = "Taichi-Maker-Pub-" + WiFi.macAddress();
  String topicString1 = "Kzeng-Pub-Temp";
  char publishTopic1[topicString1.length() + 1];  
  strcpy(publishTopic1, topicString1.c_str());
 
  // String messageString = "Hello World " + String(value++); 
  String messageString1 = String(temperature); 
  char publishMsg1[messageString1.length() + 1];   
  strcpy(publishMsg1, messageString1.c_str());
  
  // 实现ESP8266向主题发布信息
  if(mqttClient.publish(publishTopic1, publishMsg1)) {
    Serial.print("Publish Topic: ");Serial.println(publishTopic1);
    Serial.print("Publish message: ");Serial.println(publishMsg1);    
  } else {
    Serial.println("Message Publish Failed."); 
  }


  String topicString2 = "Kzeng-Pub-Humi";
  char publishTopic2[topicString2.length() + 1];  
  strcpy(publishTopic2, topicString2.c_str());
 
  String messageString2 = String(humidity); 
  char publishMsg2[messageString2.length() + 1];   
  strcpy(publishMsg2, messageString2.c_str());
  
  // 实现ESP8266向主题发布信息
  if(mqttClient.publish(publishTopic2, publishMsg2)){
    Serial.print("Publish Topic: ");Serial.println(publishTopic2);
    Serial.print("Publish message: ");Serial.println(publishMsg2);    
  } else {
    Serial.println("Message Publish Failed."); 
  }
  
}
 